package org.goodsl.mdd

import java.lang.reflect.Field
import org.goodsl.mdd.annotation.ValueType

import java.lang.annotation.Annotation
import java.lang.reflect.Method
import org.goodsl.mdd.annotation.Nullable
import org.goodsl.mdd.annotation.Setting
import org.goodsl.mdd.validator.AllowNullValidator

/**
 * Created with IntelliJ IDEA.
 * User: Simon Xiao
 * Date: 12-10-31
 * Time: 上午9:26
 * To change this template use File | Settings | File Templates.
 */
class BoxInfo implements Iterable<SegInBox> {

    private final static String VALIDATOR_FIELD = "validator"

    Class<?> boxClass
    boolean hasInit = false

    private ArrayList<Validator<Box>> validators

    private ArrayList<Validator<Box>> getValidators() {
        return validators
    }

    private void setValidators(ArrayList<Validator<Box>> vs) {
        validators = vs
    }

    private void setBoxClass(Class<?> cz) {
        this.boxClass = cz
    }

    protected TypeSetting setting
    public TypeSetting getSetting(){
        return setting
    }

    HashMap<String, SegInBox> boxSegMap = new HashMap<String, SegInBox>()
    ArrayList<SegInBox> boxSegList = new ArrayList<SegInBox>()
    HashMap<String, DependAspectInfo> dependAspects = new HashMap<String, DependAspectInfo>(3)

    BoxInfo(Class<?> cz) {
        boxClass = cz
        parseBoxClass()

        setting = new TypeSetting()
        Annotation note = cz.getAnnotation(Setting)
        if (note!=null){
            setting.reset(note)
        }
    }

    public SegInBox gerSegInBox(String segName){
        if(boxSegMap.containsKey(segName))
            return boxSegMap.get(segName)
        else
            return null
    }

    public ValidResult verify(Box box) {
        ValidResult result = new ValidResult()
        //先执行每个seg的校验,允许为空的先做空判断，为空就不执行Seg类型自带的校验
        boxSegList.each {
            ValidResult oneResult = innerVerifySeg(box,it)
            if(oneResult!=null){
                result.appendResult(oneResult,it.setting.alias)
            }
        }
        //再执行Box的校验
        for (Validator it in validators) {
            SingleValidResult<Box> singleResult = it.verify(box)
            if (singleResult == null) continue
            result.addSingleResult(singleResult)
        }
        return result
    }

    /**
     * 执行Box中指定字段的校验
     * @param box
     * @param segName
     * @return
     */
    public ValidResult verify(Box box, String segName) {
        if (!boxSegMap.containsKey(segName))
            return null

        SegInBox segInBox = boxSegMap[segName]
        innerVerifySeg(box,segInBox)

    }

    private ValidResult innerVerifySeg(Box box,SegInBox segInBox){
        String segName = segInBox.segName
        if(segInBox.isBox){
            Box innerBox = (Box) box."$segName"
            return innerBox.verify()
        }

        Seg seg = (Seg) box."$segName"
        if (segInBox.setting.nullable) {
            SingleValidResult<Seg> singleResult = AllowNullValidator.instance.verify(seg)
            if (singleResult.isValid) {
                ValidResult result = new ValidResult()
                result.addSingleResult(singleResult)
                return result
            }
            else{
                //不为空就要对已经填写的值做校验
                return seg.verify()
            }
        }else{
            return seg.verify()
        }
    }

    Box create() {
        create(false)
    }

    Box create(boolean forParse) {
        Box newBox = (Box) boxClass.newInstance()
        newBox.boxInfo = this

        boxSegMap.values().each { SegInBox segInBox ->
            Object theSeg = newBox."$segInBox.segName"
            if (theSeg == null) {
                if (segInBox.isBox) {
                    theSeg = BoxBuilder.makeBox(segInBox.boxSegType, forParse)
                    ((Box) theSeg).inTheBox = newBox
                    ((Box) theSeg).segInBox = segInBox
                }
                else {
                    theSeg = segInBox.boxSegType.newInstance()
                    ((Seg) theSeg).inTheBox = newBox
                    ((Seg) theSeg).segInBox = segInBox
                    ((Seg) theSeg).setForParse(forParse)
                    ((Seg) theSeg).segInfo = segInBox.segInfo

                }

                newBox."$segInBox.segName" = theSeg
            }
        }

        //调用用户定义的初始化方法
        try {
            Method initMethod = boxClass.getMethod("init")
            if (initMethod)
                initMethod.invoke(newBox)
        } catch (NoSuchMethodException e) {}

        //初始化变量缺省值
        boxSegMap.values().each { SegInBox segInBox ->
            if (!segInBox.isBox) {
                Object theSeg = newBox."$segInBox.segName"
                if (theSeg.value == null)
                    theSeg.value = BoxBuilder.getTypeDefaultValue(segInBox.segInfo.valueType)
            }
        }
        return newBox
    }

    private void parseBoxClass() {

        //解析内部字段
        parseBoxSegs()
        Box box4Parse = create(true)
        //解析字段的依赖关系
        parseSegDepends(box4Parse)
        //解析字段校验和组合校验信息
        parseValidator(box4Parse)
    }

    /**
     * Parse all seg in _box
     * 解析类型的字段信息，同时给每个字段增加两个便捷的读写方法
     */
    private void parseBoxSegs() {
        Field[] fs = boxClass.getDeclaredFields()
        for (Field f in fs) {
            String segName = f.name
            SegInBox segInBox = null
            if (f.name == "init") hasInit = true

            if (Box.isAssignableFrom(f.type)) {
                BoxInfo nestBoxInfo = BoxBuilder.getBoxInfo(f.type)
                segInBox = new SegInBox(f.type, null, segName, true)
                segInBox.setting = (TypeSetting)nestBoxInfo.setting.clone()

            } else {
                SegInfo segInfo = SegInfo.getSegInfo(f.type)
                if (segInfo != null) {
                    if (segName.startsWith("dep_"))
                        throw new ParseException("类型${f.type.name} 的字段 $segName 不能以 'dep_' 为前缀 ")

                    //添加一个便捷的取值方法。比如 _box 有名为 'age' 的 seg
                    //则可以使用 _box.age() 取得内部值，可以比 _box.age.value 写得便捷一点
                    boxClass.metaClass."$segName" = {->
                        delegate."$segName".value
                    }

                    boxClass.metaClass."$segName" = {arg ->
                        if(arg instanceof Closure){
                            Closure cl = (Closure)arg
                            cl.delegate.methodMissing(segName,[arg])
                        }
                        else
                            delegate."$segName".value = arg
                    }
                    segInBox = new SegInBox(f.type, segInfo, segName)
                    segInBox.setting = (TypeSetting)segInfo.setting.clone()
                }
            }

            if (segInBox != null) {
                addSeg(segInBox)

                Annotation note = f.getAnnotation(Setting)
                if (note != null) {
                    segInBox.setting.reset(note)
                    if (segInBox.setting.alias.trim() == "")
                        segInBox.setting.alias = segInBox.segName
                }
            }
        }
    }
    private void addSeg(SegInBox segInBox){
        boxSegMap.put(segInBox.segName,segInBox)
        boxSegList.add(segInBox)
    }

    private void parseSegDepends(Box box4Parse) {
        Field[] fs = boxClass.declaredFields
        for (Field f in fs) {
            if (!f.name.startsWith("dep_") || f.name.length() < 5)
                continue

            Object v = box4Parse."$f.name"
            if (!(v instanceof Closure)) //检查依赖属性的定义值是否是闭包
                throw new ParseException("${boxClass.name} 中定义的数据项依赖属性${f.name} 必须为闭包 ")

            Annotation at = null
            String dependAspectName = f.name.substring(4)
            if (dependAspectName != "value") {
                at = f.getAnnotation(ValueType)
                if (at == null)
                    throw new ParseException("${boxClass.name} 中定义的数据项依赖属性${f.name} 必须有 ValueType 标注")

            }

            //依赖侧面的名称不能跟内嵌的Box的元属性名称相同
            boxSegMap.values().each {SegInBox segInBox ->
                if (segInBox.isBox) {
                    BoxInfo nestBoxMetaInfo = BoxBuilder.getBoxInfo(segInBox.boxSegType)
                    if (nestBoxMetaInfo != null) {
                        if (nestBoxMetaInfo.boxSegMap.containsKey(dependAspectName))
                            throw new ParseException("${boxClass.name} 不能定义名为 $dependAspectName 的依赖项属性，因为其属性字段 ${segInBox.segName}的所属类型${nestBoxMetaInfo.boxClass.name} 也定义了名为 $dependAspectName 的属性。")
                    }
                }
            }

            dependAspects[dependAspectName] = new DependAspectInfo(dependAspectName, at)
            Closure cl = (Closure) v
            cl.delegate = new DependParseDelegate(box4Parse, dependAspectName, boxSegMap)
            cl.resolveStrategy = Closure.DELEGATE_FIRST
            cl()
        }
    }

    //解析校验信息
    private void parseValidator(Box box4Parse) {

        Field validField = null
        try {
            validField = boxClass.getDeclaredField(VALIDATOR_FIELD)
        }
        catch (NoSuchFieldException e) {}
        if (validField != null) {
            Object validObject = box4Parse."$VALIDATOR_FIELD"

            if (validObject != null) {
                if (!(validObject instanceof Closure)) {
                    throw new ParseException("类型${boxClass.name} 的校验器定义必须为闭包")
                }
                Closure validMaker = (Closure) validObject
                ClosureValidatorDelegate<Box> delegate = new ClosureValidatorDelegate<Box>()
                validMaker.delegate = delegate
                validMaker.resolveStrategy = Closure.DELEGATE_FIRST
                validators = validMaker()

            }
        }

    }

    public DependAspectInfo getDependAspectInfo(String dependAspectName) {
        return dependAspects[dependAspectName]
    }

    Iterator<SegInBox> iterator() {
        return boxSegList.iterator()
    }
}

/**
 * 解析数据项依赖性闭包，建立数据项之间的依赖关系
 * 主要通过 methodMissing 方法截获数据项名称，进入methodMissing
 * 的每一个方法名称必须是Box中的一个属性（其类型有MType标注)
 */
//class DependParseDelegate {
//    String dependAspectName
//    HashMap<String, SegInBox> ps
//    SegInBox dependBySeg
//    Object instance
//
//    DependParseDelegate(Object instance, String depName, HashMap<String, SegInBox> ps) {
//        this.instance = instance
//        dependAspectName = depName
//        this.ps = ps
//        dependBySeg = null
//    }
//
//    DependParseDelegate(Object instance, String depName, HashMap<String, SegInBox> ps, SegInBox dependBy) {
//        this.instance = instance
//        dependAspectName = depName
//        this.ps = ps
//        dependBySeg = dependBy
//    }
//
//    def methodMissing(String boxSegName, args) {
//        if (!ps.containsKey(boxSegName)) {
//            throw new ParseException("类型 ${instance.class.name}没有定义名为 ${boxSegName} 的属性")
//        }
//
//        SegInBox segInBox = ps[boxSegName]
//        if (dependBySeg != null)
//            dependBySeg.dependOn(dependAspectName, segInBox, true)
//
//        if (args != null && args.size() > 0 && args[0] instanceof Closure) {
//            Closure cl = (Closure) args[0]
//            DependParseDelegate newDelegate = new DependParseDelegate(instance, dependAspectName, ps, segInBox)
//            cl.delegate = newDelegate
//            cl.resolveStrategy = Closure.DELEGATE_FIRST
//            Object theSeg = instance."$boxSegName"
//
//            //闭包执行体需要被保存起来，用于运行时计算值
//            //每个 Box 的类型中，一个“属性名称+依赖项名称”映射一个闭包，用于运算时的求值
//            if (dependBySeg == null) {//第一层
//                //只对第一层的保留闭包代码，内层只用于计算
//                segInBox.dependSegCode[dependAspectName] = cl
//
//            }
//
//            //将字段本身作为闭包的默认参数.递归执行，
//            //这里是解析时间的执行，主要用于计算依赖关系
//            //todo: 考虑是否不解析嵌套的依赖
//            //if(dependBySeg==null)
//            cl(theSeg)
//
//
//        }
//    }
//
//
//}

/**
 *   <code>
 * @ValueType ( i n t )
 class OneType extends Seg {}class OneBox extends Box {
 OneType   property1
 }*   </code>
 *   for the "property" the info is:
 *   boxSegType    //-> OneType
 segName       //-> property1
 boolean isBox      //-> false
 segAnnotation  //-> int
 */

//class SegInBox {
//    Class boxSegType
//    String segName
//    boolean isBox
//    SegInfo segInfo
//
//    protected TypeSetting setting
//    public TypeSetting getSetting(){
//        return setting
//    }
//
//    HashMap<String, ArrayList<SegInBox>> dependOn = new HashMap<String, ArrayList<SegInBox>>()
//    HashMap<String, ArrayList<SegInBox>> dependBy = new HashMap<String, ArrayList<SegInBox>>()
//
//    /**
//     *   保存依赖属性的闭包，key 为依赖属性的名称
//     */
//    HashMap<String, Closure> dependSegCode = new HashMap<String, Closure>(4)
//
//
//    SegInBox(Class cz, SegInfo segInfo, String segName) {
//        this(cz, segInfo, segName, false)
//    }
//
//    SegInBox(Class cz, SegInfo segInfo, String segName, boolean box) {
//        boxSegType = cz
//        this.segName = segName
//        isBox = box
//        this.segInfo = segInfo
//    }
//
//    boolean hasDependSeg(String name) {
//        return dependSegCode.containsKey(name)
//    }
//
//    void dependOn(String dependAspectName, SegInBox other) {
//        dependOn(dependAspectName, other, false) //默认不回绕
//
//    }
//
//    void dependOn(String dependAspectName, SegInBox other, boolean loop) {
//        ArrayList<SegInBox> list = dependOn.get(dependAspectName)
//        if (list == null) {
//            list = new ArrayList<SegInBox>()
//            dependOn.put(dependAspectName, list)
//        }
//        list.add(other)
//        if (loop)
//            other.dependBy(dependAspectName, this, false)
//    }
//
//    void dependBy(String dependAspectName, SegInBox other) {
//        dependBy(dependAspectName, other, false) //默认不回绕
//
//    }
//
//    void dependBy(String dependAspectName, SegInBox other, boolean loop) {
//        ArrayList<SegInBox> list = dependBy.get(dependAspectName)
//        if (list == null) {
//            list = new ArrayList<SegInBox>()
//            dependBy.put(dependAspectName, list)
//        }
//        list.add(other)
//        if (loop)
//            other.dependOn(dependAspectName, this, false)
//    }
//
//    public void setSegValue(Box box){
//
//    }
//}

//class DependAspectInfo {
//    String aspectName
//    Annotation aspectNote
//
//    DependAspectInfo(String name, Annotation note) {
//        this.aspectName = name
//        this.aspectNote = note
//    }
//}
